package io.github.loserYa.utils;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import io.github.loserYa.log.LogConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * mq log 工具类
 *
 * @author loser
 * @date 2024/4/25
 */
public class LogUtils {

    private static final Logger logger = LoggerFactory.getLogger(LogUtils.class);

    /**
     * 日志落地
     */
    public static void push(Object data) {
        push(data, null);
    }

    /**
     * 更新日志 注意对象字段是否存在默认值
     */
    public static <T> void update(T data, T update) {
        update(data, update, null);
    }

    /**
     * 批量落地日志
     */
    public static <T> void batchPush(List<T> list) {
        batchPush(list, null);
    }

    /**
     * 获取消息发送者
     */
    private static RabbitTemplate getRabbitTemplate() {
        return RabbitMqUtil.get(RabbitMqUtil.getLogPre());
    }

    /**
     * 批量更新
     * 可以指定表名
     * 大驼峰会转换为下划线
     */
    public static <T> void batchPush(List<T> list, String table) {

        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        String tableName = table;
        if (StringUtils.isEmpty(tableName)) {
            tableName = list.get(0).getClass().getSimpleName();
        }
        List<List<T>> partition = Lists.partition(list, RabbitMqUtil.getSize());
        for (List<T> ts : partition) {
            try {
                List<JSONObject> array = ts.stream().map(JSONObject::from).collect(Collectors.toList());
                JSONObject pkg = new JSONObject();
                pkg.put(LogConstant.TABLE, tableName);
                pkg.put(LogConstant.LIST, array);
                RabbitTemplate template = getRabbitTemplate();
                template.convertAndSend(RabbitMqUtil.getLogExchange(), "", pkg);
            } catch (Exception ex) {
                logger.error("batchPush ts {} table {}", JSONArray.toJSONString(ts), table, ex);
            }
        }

    }

    /**
     * 日志落地
     */
    public static void push(Object data, String table) {

        if (Objects.isNull(data)) {
            return;
        }
        if (isPrimitiveObj(data)) {
            return;
        }
        try {
            JSONObject jsonObject = JSONObject.from(data);
            String tableName = StringUtils.isEmpty(table) ? data.getClass().getSimpleName() : table;
            jsonObject.put(LogConstant.TABLE, tableName);
            RabbitTemplate template = getRabbitTemplate();
            template.convertAndSend(RabbitMqUtil.getLogExchange(), "", jsonObject);
        } catch (Exception ex) {
            logger.error("push error data {} table {}", JSONObject.toJSONString(data), table, ex);
        }

    }

    /**
     * 更新日志
     */
    public static <T> void update(T data, T update, String table) {

        if (Objects.isNull(data) || Objects.isNull(update)) {
            return;
        }
        if (isPrimitiveObj(data) || isPrimitiveObj(update)) {
            return;
        }
        try {
            JSONObject jsonObject = JSONObject.from(data);
            String tableName = StringUtils.isEmpty(table) ? data.getClass().getSimpleName() : table;
            jsonObject.put(LogConstant.TABLE, tableName);
            jsonObject.put(LogConstant.UPDATE, JSONObject.from(update));
            RabbitTemplate template = getRabbitTemplate();
            template.convertAndSend(RabbitMqUtil.getLogExchange(), "", jsonObject);
        } catch (Exception ex) {
            logger.error("update error data {} update {} table {}", JSONObject.toJSONString(data), JSONObject.toJSONString(update), table, ex);
        }

    }

    /**
     * 是否是基本类型
     */
    private static boolean isPrimitiveObj(Object obj) {
        return obj.getClass().isPrimitive() || obj instanceof String || obj instanceof Integer || obj instanceof Long || obj instanceof Double || obj instanceof Float || obj instanceof Boolean || obj instanceof Byte || obj instanceof Short || obj instanceof Character;
    }

}
